﻿#include "framework.h"
#include "Block.h"

// ███
// █

// 全局变量
extern ColorGrid gExistentBlocks[GAME_BOARD_GRID_COUNT_V][GAME_BOARD_GRID_COUNT_H];

// 函数声明
static void Block6_Erase(Block*);
static int Block6_GetBottom(Block*);
static int Block6_GetTop(Block*);
static void Block6_HandleCannotMoveDown(Block*);
static BOOL Block6_MoveDown(Block*);
static void Block6_MoveLeft(Block*);
static void Block6_MoveRight(Block*);
static void Block6_Transform(Block*);

/**
 * 创建方块6。
 * @return 方块6
 */
Block* New_Block6() {
    // 创建方块
    Block* block = New_Block();

    // 初始化数据
    block->mBlocks[1][0].mUsed = block->mBlocks[1][1].mUsed = block->mBlocks[1][2].mUsed = block->mBlocks[2][0].mUsed = TRUE;

    // 初始化函数
    block->enterPreview = Block_EnterPreview;
    block->erase = Block6_Erase;
    block->getBottom = Block6_GetBottom;
    block->getTop = Block6_GetTop;
    block->handleCannotMoveDown = Block6_HandleCannotMoveDown;
    block->moveDown = Block6_MoveDown;
    block->moveLeft = Block6_MoveLeft;
    block->moveRight = Block6_MoveRight;
    block->transform = Block6_Transform;

    return block;
}

/**
 * 擦除。
 * @param block 方块6
 */
static void Block6_Erase(Block* block) {
    RECT rect = { 0 };

    switch (block->mShape) {
        case ONE:
            rect.left = GRID_SIZE * block->mLine;
            rect.top = GRID_SIZE * (block->mRow + 1);
            rect.right = rect.left + GRID_SIZE * 3;
            rect.bottom = rect.top + GRID_SIZE;
            block->eraseRect(block, &rect);
            rect.left = GRID_SIZE * block->mLine;
            rect.top = GRID_SIZE * (block->mRow + 2);
            rect.right = rect.left + GRID_SIZE;
            rect.bottom = rect.top + GRID_SIZE;
            block->eraseRect(block, &rect);
            break;
        case TWO:
            rect.left = GRID_SIZE * block->mLine;
            rect.top = GRID_SIZE * block->mRow;
            rect.right = rect.left + GRID_SIZE;
            rect.bottom = rect.top + GRID_SIZE;
            block->eraseRect(block, &rect);
            rect.left = GRID_SIZE * (block->mLine + 1);
            rect.top = GRID_SIZE * block->mRow;
            rect.right = rect.left + GRID_SIZE;
            rect.bottom = rect.top + GRID_SIZE * 3;
            block->eraseRect(block, &rect);
            break;
        case THREE:
            rect.left = GRID_SIZE * (block->mLine + 2);
            rect.top = GRID_SIZE * block->mRow;
            rect.right = rect.left + GRID_SIZE;
            rect.bottom = rect.top + GRID_SIZE;
            block->eraseRect(block, &rect);
            rect.left = GRID_SIZE * block->mLine;
            rect.top = GRID_SIZE * (block->mRow + 1);
            rect.right = rect.left + GRID_SIZE * 3;
            rect.bottom = rect.top + GRID_SIZE;
            block->eraseRect(block, &rect);
            break;
        case FOUR:
            rect.left = GRID_SIZE * (block->mLine + 1);
            rect.top = GRID_SIZE * block->mRow;
            rect.right = rect.left + GRID_SIZE;
            rect.bottom = rect.top + GRID_SIZE * 3;
            block->eraseRect(block, &rect);
            rect.left = GRID_SIZE * (block->mLine + 2);
            rect.top = GRID_SIZE * (block->mRow + 2);
            rect.right = rect.left + GRID_SIZE;
            rect.bottom = rect.top + GRID_SIZE;
            block->eraseRect(block, &rect);
            break;
    }
}

/**
 * 获取底端所在的行数。底端是指方块最下方的有效格。
 * @param block 方块6
 * @return 底端所在的行数
 */
static int Block6_GetBottom(Block* block) {
    if (block->mShape == THREE) {
        return block->mRow + 1;
    }
    return block->mRow + 2;
}

/**
 * 获取顶端所在的行数。顶端是指方块最上方的有效格。
 * @param block 方块6
 * @return 顶端所在的行数
 */
static int Block6_GetTop(Block* block) {
    if (block->mShape == ONE) {
        return block->mRow + 1;
    }
    return block->mRow;
}

/**
 * 对不能下落的处理。
 * @param block 方块6
 */
static void Block6_HandleCannotMoveDown(Block* block) {
    switch (block->mShape) {
        case ONE:
            gExistentBlocks[block->mRow + 1][block->mLine].mUsed =
            gExistentBlocks[block->mRow + 1][block->mLine + 1].mUsed =
            gExistentBlocks[block->mRow + 1][block->mLine + 2].mUsed =
            gExistentBlocks[block->mRow + 2][block->mLine].mUsed = TRUE;
            gExistentBlocks[block->mRow + 1][block->mLine].mColor =
            gExistentBlocks[block->mRow + 1][block->mLine + 1].mColor =
            gExistentBlocks[block->mRow + 1][block->mLine + 2].mColor =
            gExistentBlocks[block->mRow + 2][block->mLine].mColor = block->mColor;
            break;
        case TWO:
            gExistentBlocks[block->mRow][block->mLine].mUsed =
            gExistentBlocks[block->mRow][block->mLine + 1].mUsed =
            gExistentBlocks[block->mRow + 1][block->mLine + 1].mUsed =
            gExistentBlocks[block->mRow + 2][block->mLine + 1].mUsed = TRUE;
            gExistentBlocks[block->mRow][block->mLine].mColor =
            gExistentBlocks[block->mRow][block->mLine + 1].mColor =
            gExistentBlocks[block->mRow + 1][block->mLine + 1].mColor =
            gExistentBlocks[block->mRow + 2][block->mLine + 1].mColor = block->mColor;
            break;
        case THREE:
            gExistentBlocks[block->mRow][block->mLine + 2].mUsed =
            gExistentBlocks[block->mRow + 1][block->mLine].mUsed =
            gExistentBlocks[block->mRow + 1][block->mLine + 1].mUsed =
            gExistentBlocks[block->mRow + 1][block->mLine + 2].mUsed = TRUE;
            gExistentBlocks[block->mRow][block->mLine + 2].mColor =
            gExistentBlocks[block->mRow + 1][block->mLine].mColor =
            gExistentBlocks[block->mRow + 1][block->mLine + 1].mColor =
            gExistentBlocks[block->mRow + 1][block->mLine + 2].mColor = block->mColor;
            break;
        case FOUR:
            gExistentBlocks[block->mRow][block->mLine + 1].mUsed =
            gExistentBlocks[block->mRow + 1][block->mLine + 1].mUsed =
            gExistentBlocks[block->mRow + 2][block->mLine + 1].mUsed =
            gExistentBlocks[block->mRow + 2][block->mLine + 2].mUsed = TRUE;
            gExistentBlocks[block->mRow][block->mLine + 1].mColor =
            gExistentBlocks[block->mRow + 1][block->mLine + 1].mColor =
            gExistentBlocks[block->mRow + 2][block->mLine + 1].mColor =
            gExistentBlocks[block->mRow + 2][block->mLine + 2].mColor = block->mColor;
            break;
    }
}

/**
 * 下落。
 * @param block 方块6
 * @return 成功则返回 TRUE，否则返回 FALSE
 */
static BOOL Block6_MoveDown(Block* block) {
    switch (block->mShape) {
        case ONE:
            if (block->mRow == 17) {
                block->handleCannotMoveDown(block);
                return FALSE;
            }
            if (gExistentBlocks[block->mRow + 3][block->mLine].mUsed ||
                gExistentBlocks[block->mRow + 2][block->mLine + 1].mUsed ||
                gExistentBlocks[block->mRow + 2][block->mLine + 2].mUsed) {
                block->handleCannotMoveDown(block);
                return FALSE;
            }
            break;
        case TWO:
            if (block->mRow == 17) {
                block->handleCannotMoveDown(block);
                return FALSE;
            }
            if (gExistentBlocks[block->mRow + 1][block->mLine].mUsed ||
                gExistentBlocks[block->mRow + 3][block->mLine + 1].mUsed) {
                block->handleCannotMoveDown(block);
                return FALSE;
            }
            break;
        case THREE:
            if (block->mRow == 18) {
                block->handleCannotMoveDown(block);
                return FALSE;
            }
            if (gExistentBlocks[block->mRow + 2][block->mLine].mUsed ||
                gExistentBlocks[block->mRow + 2][block->mLine + 1].mUsed ||
                gExistentBlocks[block->mRow + 2][block->mLine + 2].mUsed) {
                block->handleCannotMoveDown(block);
                return FALSE;
            }
            break;
        case FOUR:
            if (block->mRow == 17) {
                block->handleCannotMoveDown(block);
                return FALSE;
            }
            if (gExistentBlocks[block->mRow + 3][block->mLine + 1].mUsed ||
                gExistentBlocks[block->mRow + 3][block->mLine + 2].mUsed) {
                block->handleCannotMoveDown(block);
                return FALSE;
            }
            break;
    }

    return Block_MoveDown(block);
}

/**
 * 左移。
 * @param block 方块6
 */
static void Block6_MoveLeft(Block* block) {
    switch (block->mShape) {
        case ONE:
            if (block->mLine == 0) {
                return;
            }
            if (gExistentBlocks[block->mRow + 1][block->mLine - 1].mUsed || 
                gExistentBlocks[block->mRow + 2][block->mLine - 1].mUsed) {
                return;
            }
            break;
        case TWO:
            if (block->mLine == 0) {
                return;
            }
            if (gExistentBlocks[block->mRow][block->mLine - 1].mUsed || 
                gExistentBlocks[block->mRow + 1][block->mLine].mUsed || 
                gExistentBlocks[block->mRow + 2][block->mLine].mUsed) {
                return;
            }
            break;
        case THREE:
            if (block->mLine == 0) {
                return;
            }
            if (gExistentBlocks[block->mRow][block->mLine + 1].mUsed || 
                gExistentBlocks[block->mRow + 1][block->mLine - 1].mUsed) {
                return;
            }
            break;
        case FOUR:
            if (block->mLine == -1) {
                return;
            }
            if (gExistentBlocks[block->mRow][block->mLine].mUsed || 
                gExistentBlocks[block->mRow + 1][block->mLine].mUsed || 
                gExistentBlocks[block->mRow + 2][block->mLine].mUsed) {
                return;
            }
            break;
    }

    Block_MoveLeft(block);
}

/**
 * 右移。
 * @param block 方块6
 */
static void Block6_MoveRight(Block* block) {
    switch (block->mShape) {
        case ONE:
            if (block->mLine == 7) {
                return;
            }
            if (gExistentBlocks[block->mRow + 1][block->mLine + 3].mUsed || 
                gExistentBlocks[block->mRow + 2][block->mLine + 1].mUsed) {
                return;
            }
            break;
        case TWO:
            if (block->mLine == 8) {
                return;
            }
            if (gExistentBlocks[block->mRow][block->mLine + 2].mUsed || 
                gExistentBlocks[block->mRow + 1][block->mLine + 2].mUsed || 
                gExistentBlocks[block->mRow + 2][block->mLine + 2].mUsed) {
                return;
            }
            break;
        case THREE:
            if (block->mLine == 7) {
                return;
            }
            if (gExistentBlocks[block->mRow][block->mLine + 3].mUsed || 
                gExistentBlocks[block->mRow + 1][block->mLine + 3].mUsed) {
                return;
            }
            break;
        case FOUR:
            if (block->mLine == 7) {
                return;
            }
            if (gExistentBlocks[block->mRow][block->mLine + 2].mUsed || 
                gExistentBlocks[block->mRow + 1][block->mLine + 2].mUsed || 
                gExistentBlocks[block->mRow + 2][block->mLine + 3].mUsed) {
                return;
            }
            break;
    }

    Block_MoveRight(block);
}

/**
 * 变形。
 * @param block 方块6
 */
static void Block6_Transform(Block* block) {
    switch (block->mShape) {
        case ONE:
            if (block->mRow == -1) {
                return;
            }
            if (gExistentBlocks[block->mRow][block->mLine].mUsed || 
                gExistentBlocks[block->mRow][block->mLine + 1].mUsed || 
                gExistentBlocks[block->mRow + 2][block->mLine + 1].mUsed) {
                return;
            }
            block->erase(block);
            block->mBlocks[1][0].mUsed = block->mBlocks[1][2].mUsed = block->mBlocks[2][0].mUsed = FALSE;
            block->mBlocks[0][0].mUsed = block->mBlocks[0][1].mUsed = block->mBlocks[2][1].mUsed = TRUE;
            block->mShape = TWO;
            break;
        case TWO:
            if (block->mLine == 8) {
                return;
            }
            if (gExistentBlocks[block->mRow][block->mLine + 2].mUsed || 
                gExistentBlocks[block->mRow + 1][block->mLine].mUsed || 
                gExistentBlocks[block->mRow + 1][block->mLine + 2].mUsed) {
                return;
            }
            block->erase(block);
            block->mBlocks[0][0].mUsed = block->mBlocks[0][1].mUsed = block->mBlocks[2][1].mUsed = FALSE;
            block->mBlocks[0][2].mUsed = block->mBlocks[1][0].mUsed = block->mBlocks[1][2].mUsed = TRUE;
            block->mShape = THREE;
            break;
        case THREE:
            if (block->mRow == 18) {
                return;
            }
            if (gExistentBlocks[block->mRow][block->mLine + 1].mUsed || 
                gExistentBlocks[block->mRow + 2][block->mLine + 1].mUsed || 
                gExistentBlocks[block->mRow + 2][block->mLine + 2].mUsed) {
                return;
            }
            block->erase(block);
            block->mBlocks[0][2].mUsed = block->mBlocks[1][0].mUsed = block->mBlocks[1][2].mUsed = FALSE;
            block->mBlocks[0][1].mUsed = block->mBlocks[2][1].mUsed = block->mBlocks[2][2].mUsed = TRUE;
            block->mShape = FOUR;
            break;
        case FOUR:
            if (block->mLine == -1) {
                return;
            }
            if (gExistentBlocks[block->mRow + 1][block->mLine].mUsed || 
                gExistentBlocks[block->mRow + 1][block->mLine + 2].mUsed || 
                gExistentBlocks[block->mRow + 2][block->mLine + 2].mUsed) {
                return;
            }
            block->erase(block);
            block->mBlocks[0][1].mUsed = block->mBlocks[2][1].mUsed = block->mBlocks[2][2].mUsed = FALSE;
            block->mBlocks[1][0].mUsed = block->mBlocks[1][2].mUsed = block->mBlocks[2][0].mUsed = TRUE;
            block->mShape = ONE;
            break;
    }

    block->draw(block);
}
